package fi.hell.util.mail

import java.security.Security
import java.util.Properties
import org.apache.log4j.*
import javax.mail.Message
import javax.mail.MessagingException
import javax.mail.SendFailedException
import javax.mail.Session
import javax.mail.Transport
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeMessage
import javax.mail.BodyPart
import javax.mail.Multipart
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import javax.activation.*;
import javax.mail.PasswordAuthentication;
import javax.mail.Authenticator;

/**
 *
 * @author Jukka
 */
public class Mailer {
    Message message
    String text
    String recipients = ""
    MimeBodyPart htmlMessage
    MimeBodyPart plainTextMessage
    List attachmentList = []
    Transport transport

    private final Logger log = Logger.getLogger(getClass())

    public Mailer(def host, def port) {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider())
		boolean debug = false

		Properties props = new Properties()
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.user", "jukka");
		props.put("mail.smtp.host", host)
		props.put("mail.smtp.auth", true)
		props.put("mail.debug", false)
		props.put("mail.smtp.port", port)
        props.put("mail.smtp.localhost", "mail.hell.fi")
		props.put("mail.smtp.socketFactory.port", port)
		props.put("mail.smtp.socketFactory.fallback", false)
        props.put("mail.smtp.starttls.enable", true);
        props.put("mail.smtp.starttls.required", true);
        
        Authenticator auth = new SMTPAuthenticator();
		Session session = Session.getDefaultInstance(props, auth)
        transport = session.getTransport()
        log.debug "Session created"
		session.setDebug(debug)

        // Define message
        message = new MimeMessage(session)
    }

    def setFrom(def from) {
        message.setFrom(new InternetAddress(from))
    }

    def setRecipients(def recipients) {
        this.recipients = ""
        InternetAddress[] addressTo = new InternetAddress[recipients.size()]
		def i = 0
        recipients.each {
            addressTo[i] = new InternetAddress(it)
            this.recipients += it + " "
            i++
		}
		message.setRecipients(Message.RecipientType.TO, addressTo)
    }

    def setSubject(def subject) {
        message.setSubject(subject)
    }

    def setMessageText(def text) {

        if(text) {
            // Create the message part
            plainTextMessage = new MimeBodyPart()

			plainTextMessage.setText(text, "utf-8")
			plainTextMessage.setHeader("Content-Type", "text/plain; charset=\"utf-8\"")
			plainTextMessage.setHeader("Content-Transfer-Encoding", "quoted-printable")

            // Fill the message
			plainTextMessage.setContent(text,"text/plain; charset=\"UTF-8\"")
        }
    }

    def setHtmlMessage(def html) {

        if(html) {
            // Create the message part
            htmlMessage = new MimeBodyPart()

			htmlMessage.setText(html, "utf-8")
			htmlMessage.setHeader("Content-Type", "text/plain; charset=\"utf-8\"")
			htmlMessage.setHeader("Content-Transfer-Encoding", "quoted-printable")

            // Fill the message
            htmlMessage.setContent(html, "text/html; charset=\"UTF-8\"")
        }
    }

    /**
     * Set attachments to this email
     * @param Map Filenames as key and files as value to be attached
     */
    def setAttachments(def attachments) {
        log.debug "Attaching ${attachments.size()} files"

        attachments.each { filename, file ->
            // Create second body part
            MimeBodyPart attachment = new MimeBodyPart()

            DataSource source
            // Get the attachment
            if(file instanceof File)
                source = new FileDataSource(file)
            else
                source = file

            // Set the data handler to the attachment
            DataHandler dh = new DataHandler(source)
            attachment.setDataHandler(dh)
            attachment.setHeader("Content-Type", dh.getContentType())

            // Set the filename
            attachment.setFileName(filename)

            attachmentList += attachment
        }
    }

	def sendMail(def inReplyTo) throws MessagingException {
        if(plainTextMessage || htmlMessage) {
            Multipart alternative = new MimeMultipart("alternative")

            // Add body parts
            if(plainTextMessage) {
                log.debug "Setting plain text part..."
                alternative.addBodyPart(plainTextMessage)
            }

            if(htmlMessage) {
                log.debug "Setting html part..."
                alternative.addBodyPart(htmlMessage)
            }

            if(attachmentList.size() > 0) {
                log.debug "Setting attachments part(s)..."
                Multipart mixed = new MimeMultipart("mixed");
                MimeBodyPart wrap = new MimeBodyPart();
                wrap.setContent(alternative); // Set alternative multipart for mixed multipart
                mixed.addBodyPart(wrap);
                attachmentList.each {
                    mixed.addBodyPart(it);
                }
                message.setContent(mixed)
            }
            else
                message.setContent(alternative)

            if (inReplyTo) {
                message.setHeader("In-Reply-To", inReplyTo)
            }

            log.debug "Sending mail to ${recipients}"

            def success = true
            try {
                transport.connect()
                transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
                transport.close()
            } catch (SendFailedException e) {
                log.error("Sending mail failed. Reason: ${e.getMessage()}",e)
                success = false
            } catch (MessagingException e) {
                log.error("Messaging exception occurred. Reason: ${e.getMessage()}",e)
                success = false
            } catch (Exception e) {
                log.error("Exception occurred. Reason: ${e.getMessage()}",e)
                success = false
            }
            if (success)
                log.debug "Mail(s) sent"

            return success
        }
        else {
            log.error "Plain text or html text was not set. setPlainText or setHtml shoud be called."
            return false
        }
	}

    private class SMTPAuthenticator extends javax.mail.Authenticator {
        public PasswordAuthentication getPasswordAuthentication() {
           String username = "poll";
           String password = "";
           return new PasswordAuthentication(username, password);
        }
    }
}
